package com.ifnk.portaljava.hlyt.test;

import com.ifnk.portaljava.dapWeb.dapweb.CDRBean;
import com.ifnk.portaljava.hlyt.service.IDeviceLookupService;
import com.ifnk.portaljava.hlyt.springutil.ServiceLocator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.*;
import org.dom4j.io.SAXReader;

import java.io.*;
import java.util.*;

public class Tshark3 {
	
    private static Log loger = LogFactory.getLog(Tshark3.class);
    public static String tshark;
    public static String pcapfilepath;
    public static String pcapNativeFile;
    public static String psml;
    public static String pdml;
    
    private final static String de = ",";

    static
    {
        Locale locale = Locale.ENGLISH;
        ResourceBundle localResource = ResourceBundle.getBundle("Socket", locale);
        tshark = localResource.getString("tshark");
        pcapfilepath = localResource.getString("pacpfilepath");
        psml = localResource.getString("psml");
        pdml = localResource.getString("pdml");
        pcapNativeFile = localResource.getString("pcapNativeFile");
    }

    private Document detailXml;
    public Document getDetailXml() {
		return detailXml;
	}

	public Document getSummaryXml() {
		return summaryXml;
	}

	private Document summaryXml;
    private List<String> summaries;
    public List<String> getSummaries() {
		return summaries;
	}

	public List<String> getDetails() {
		return details;
	}

	private List<String> details;
    private String filename;
    
    private byte[][] packets;
    public byte[] getPKT(int no) {
    	
    	if (packets != null && no < packets.length) {
    		return packets[no];
    	} else
    		return null;
    }
    
    //private String sessionId;
    
    public Tshark3(byte[] pcap, String sessionid)
    {
        //this.sessionId = NetUtility.getUuid();
        		
        this.filename = pcapfilepath + "summary" + File.separator + sessionid +
            File.separator + "all.pcap";

        try
        {
            Tshark3.savePacketToNativeFile(filename, pcap, false);
        }
        catch (IOException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        summaryXml = getSummaryDecodingXML();
        detailXml = getDetailedDecodingXML();
        phaseXml2String();
    }
    
    public Tshark3(String filename, String sessionid) {
    	this.filename = filename;
    	
        this.filename = pcapfilepath + "summary" + File.separator 
	        + sessionid + File.separator + filename;
        
        summaryXml = getSummaryDecodingXML();
        detailXml = getDetailedDecodingXML();
        phaseXml2String();
        this.packets = getPackets();
    	
    }
    
    private byte[][] getPackets() {
        packets = new byte[details.size()][];
    	File fp = new File(this.filename);
        InputStream in;
		try {
			in = new FileInputStream(this.filename);
	        byte[] pcap = new byte[(int) fp.length()];
	        in.read(pcap);
	        
	        int offset = 24;
	    	for (int i = 0; i < details.size(); i++) {
	    		offset += 8; // timestamp
	    		System.out.println(pcap[offset]);
	    		System.out.println(pcap[offset]& 0xff);
	    		int length = (pcap[offset] & 0xff) + (pcap[offset + 1] << 8 & 0x0000ff00) + (pcap[offset + 2] << 16 & 0x00ff0000)
	    					+ (pcap[offset + 3] << 24 & 0xff000000);
	    		offset += 8;
	    		byte p[] = new byte[length];
	    		System.arraycopy(pcap, offset , p, 0, length);
	    		packets[i] = p;
	    		offset += length;
	    	}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
	    	return packets;
		}
	}

	private void phaseXml2String() {
    	
    	summaries = new ArrayList<String>();
    	details = new ArrayList<String>();
    	

        if (this.summaryXml != null)
        {
            Element root = summaryXml.getRootElement();
            Iterator<?> it = root.elementIterator();
            while (it.hasNext())
            {
                Element pack = (Element) it.next();
		        StringBuffer summary = new StringBuffer();
                summary.append(pack.element("No").getText());
                summary.append(de);
                summary.append(pack.element("Time").getText());
                summary.append(de);
                summary.append(pack.element("Source").getText());
                summary.append(de);
                summary.append(pack.element("Destination").getText());
                summary.append(de);
                summary.append(pack.element("Protocol").getText());
                summary.append(de);
                summary.append(pack.element("Length").getText());
                summary.append(de);
                summary.append(pack.element("Info").getText().replaceAll(",", "，"));
                summary.append("\n");
                summaries.add(summary.toString());
            }
        }
        
        if (this.detailXml != null)
        {
        	List<?> packes = detailXml.selectNodes("//packet");
        	
        	Iterator<?> it = packes.iterator();
        	
        	while(it.hasNext())
        	{
        		Element pack = (Element) it.next();
        		details.add(pack.asXML());
        	}
        	
        }
    }
    
    public String getCdrDetail(int pno)
    {
        if (detailXml != null)
        {
            Element p = (Element) detailXml.selectNodes("//packet").get(pno);

            if (p != null)
            {
                return p.asXML();
            }
        }

        return null;
    }

    public String getCdrSummary(int pno)
    {
        StringBuffer summary = new StringBuffer();

        if (this.summaryXml != null)
        {
            Element root = summaryXml.getRootElement();

            Iterator<?> it = root.elementIterator();
            int i = 0;

            while (it.hasNext())
            {
                if (++i == pno)
                {
                    Element pack = (Element) it.next();
                    summary.append(pack.element("No").getText());
                    summary.append(de);
                    summary.append(pack.element("Time").getText());
                    summary.append(de);
                    summary.append(pack.element("Source").getText());
                    summary.append(de);
                    summary.append(pack.element("Destination").getText());
                    summary.append(de);
                    summary.append(pack.element("Protocol").getText());
                    summary.append(de);
                    summary.append(pack.element("Length").getText());
                    summary.append(de);
                    summary.append(pack.element("Info").getText().replaceAll(",", "，"));
                    summary.append("\n");

                    return summary.toString();
                }
            }
        }

        return null;
    }
    
    public String getCdrTimestamp(int pno) {
    	
    	
        if (this.summaryXml != null)
        {
            Element root = summaryXml.getRootElement();

            Iterator<?> it = root.elementIterator();
            int i = 0;

            while (it.hasNext())
            {
                if (++i == pno)
                {
                    Element pack = (Element) it.next();
                    return pack.element("Time").getText();
                }
            }
        }
        return null;
    	
    }

    public void finish()
    {
    	File f = new File(filename);
        System.out.println(f.getParent());
        File p = new File(f.getParent());
        Tshark3.deleteFile(f);
        Tshark3.deleteFile(p);
    }

    public static Document readXMLFile(InputStream in)
        throws DocumentException, IOException
    {
        SAXReader sax = new SAXReader();

        sax.setEncoding("GBK");

        Document document = sax.read(in);
        Element root = document.getRootElement();

        // 取得structure节点
        Element structure = root.element("structure");

        // 取得structure节点的所有子节点
        List nodes = structure.elements();
        Iterator its = nodes.iterator();
        List header = new ArrayList();

        while (its.hasNext())
        {
            Element section = (Element) its.next();
            String value = section.getText();
            value = value.replace(" ", "_");

            if ("No.".equals(value))
            {
                value = "No";
            }

            header.add(value);
        }

        // 取得所有的packet节点的集合
        List packets = root.elements("packet");
        Iterator ps = packets.iterator();
        List values = new ArrayList();

        while (ps.hasNext())
        {
            // 每一个packet节点
            Element packet = (Element) ps.next();

            // 给packet添加SequenceNo属性
            // 取得packet节点下的所有的section节点的集合
            List sections = packet.elements();
            Iterator it = sections.iterator();
            List value = new ArrayList();

            while (it.hasNext())
            {
                // 每一个section节点
                Element element = (Element) it.next();

                // 取得section节点的值
                String text = element.getText();
                value.add(text);
            }

            values.add(value);
        }

        return XMLDocumenttoString(header, values);
    }

    public static void savePacketToNativeFile(String filename, byte[] packet,
        boolean append) throws IOException
    {
        File file = new File(filename);
        File parentFile = file.getParentFile();

        if (!parentFile.exists())
        {
            parentFile.mkdirs();
        }

        DataOutputStream output = new DataOutputStream(new FileOutputStream(
                    file, append));
        output.write(packet);
        output.flush();
        output.close();
    }

    private static InputStream RunTshark(String tsharkcmd)
    {
        InputStream in = null;

        try
        {
            Process process = Runtime.getRuntime().exec(tsharkcmd);
            in = new BufferedInputStream(process.getInputStream());

            int i = 0;

            while (true)
            {
                if (in.available() <= 0)
                {
                    i++;

                    if (i > 20)
                    {
                        i = 0;

                        break;
                    }

                    try
                    {
                        Thread.sleep(200);
                    }
                    catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }

                    continue;
                }
                else if (in.available() > 0)
                {
                    i = 0;

                    break;
                }
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

        return in;
    }

    private static Document XMLDocumenttoString(List header, List values)
    {
        Document document = DocumentHelper.createDocument();
        Element root = document.addElement("root");
        Iterator it = values.iterator();

        while (it.hasNext())
        {
            Element packet = root.addElement("packet");
            List list = (List) it.next();
            Iterator valueIt = list.iterator();
            Iterator headIt = header.iterator();

            while (valueIt.hasNext() && headIt.hasNext())
            {
                String field = (String) headIt.next();
                String fakevalue = (String) valueIt.next();

               IDeviceLookupService dlup = (IDeviceLookupService) ServiceLocator.getBean("IDeviceLookupService");
               String realvalue = null;
               try {
                       realvalue = dlup.findDeviceName(fakevalue);
               } catch (Exception e) {
                       // TODO Auto-generated catch block
                       e.printStackTrace();
               }
               if(realvalue != null) {
                       fakevalue = realvalue;
               }

                /*
                   packet.addElement((String) field).setText(
                                   (String) valueIt.next());
                 */
                packet.addElement((String) field).setText(fakevalue);
            }
        }

        return document;
    }

    private static boolean deleteFile(File file)
    {
        //		File file = new File(fileName);
        boolean flag = true;

        if (file.exists())
        {
            if (file.isDirectory())
            {
                File[] children = file.listFiles();

                for (int i = 0; i < children.length; i++)
                {
                    flag = flag && deleteFile(children[i]);
                }
            }

            flag = flag && file.delete();
        }

        return flag;
    }

    private static Document parse(InputStream inn)
        throws IOException, DocumentException
    {
        SAXReader sax = new SAXReader();
        InputStreamReader strInStream = new InputStreamReader(inn, "GBK");

        //File justfile = new File("c:\\root\\d\\portable\\WiresharkPortable\\App\\Wireshark\\test.xml");
        //FileInputStream justtest = new FileInputStream(justfile);
        //InputStreamReader strInStream = new InputStreamReader(justtest);
        //Document document = sax.read(new BufferedInputStream(new FileInputStream("c:\\root\\d\\portable\\WiresharkPortable\\App\\Wireshark\\test.xml")));
        Document document = sax.read(strInStream);

        // 将proto节点的名字改为field
        List pro = document.selectNodes("//proto");
        Iterator itr = pro.iterator();

        while (itr.hasNext())
        {
            Element element = (Element) itr.next();
            element.setName("field");
        }

        // commit out in cleaning coding round
        //String xml = null;
        List list = document.selectNodes("//field");
        Iterator it = list.iterator();
        int i = 1;

        while (it.hasNext())
        {
            Element fieldElement = (Element) it.next();
            Attribute attr = fieldElement.attribute("showname");

            // 如果没有showname属性，则获取show属性值并把show属性改为showname
            if (attr == null)
            {
                attr = fieldElement.attribute("show");

                if (attr != null)
                {
                    fieldElement.addAttribute("showname", attr.getValue());
                    fieldElement.remove(attr);
                }
                else
                { // if show is null then
                  /*
                     */
                    attr = fieldElement.attribute("name");
                    fieldElement.addAttribute("showname", attr.getValue());
                }
            }

            fieldElement.addAttribute("id", "" + i++);

            Attribute hide = fieldElement.attribute("hide");

            if ((hide != null) && "yes".equals(hide.getValue()))
            {
                fieldElement.getParent().remove(fieldElement);
            }
        }

        // 删除name=geninfo的节点
        Iterator geninfos = document.getRootElement()
                                    .selectNodes("//field[@name='geninfo']")
                                    .iterator();
        Iterator packets = document.selectNodes("//packet").iterator();

        while (packets.hasNext())
        {
            if (geninfos.hasNext())
            {
                Element node = (Element) geninfos.next();
                ((Element) packets.next()).remove(node);
            }
        }

        // 删除packet节点
        // why delete packet nodes when packet size == 1 ???
        /*
           if (document.getRootElement().elements().size() == 1) {
                   Element packet = document.getRootElement().element("packet");
                   List nodes = packet.elements();
                   document.getRootElement().remove(packet);
                   document.getRootElement().setContent(nodes);
           }
         */
        List lists = document.selectNodes("//field");
        Iterator its = lists.iterator();

        while (its.hasNext())
        {
            Element field = (Element) its.next();

            if ((field.attribute("show") == null) &&
                    (field.attribute("showname") == null))
            {
                List fiel = field.elements();

                if (fiel.size() > 0)
                {
                    Element first = (Element) fiel.get(0);
                    List second = first.elements();
                    List itor = first.attributes();
                    field.setAttributes(itor);
                    field.remove(first);
                    field.setContent(second);
                }
            }
        }

        return document;
    }

    private static CDRBean readBinaryToString(byte[] data, CDRBean cdrBean)
    {
        String pktStr = "";

        for (int i = 0; i < data.length; i++)
        {
            pktStr += (Integer.toHexString(data[i] & 0xFF) + "; ");
        }

        //十六进制的数据
        StringBuilder binary = new StringBuilder();
        StringBuilder text = new StringBuilder();
        byte temp = 0;

        for (int i = 0; i < data.length; i++)
        {
            temp = data[i];

            // 以十六进制的无符号整数形式返回一个字符串表示形式。
            String str = Integer.toHexString(temp);

            if (str.length() == 8)
            { //去掉补位的f
                str = str.substring(6);
            }

            if (str.length() == 1)
            {
                str = "0" + str;
            }

            binary.append(str.toUpperCase());

            //转换成ascii码
            String ascii = "";

            if ((temp > 34) && (temp < 127))
            {
                char c = (char) temp;
                ascii = c + "";
            }
            else
            {
                ascii = ".";
            }

            text.append(ascii);
        }

        //计算行数
        int line = ((text.toString().length() % 16) == 0)
            ? (text.toString().length() / 16)
            : ((text.toString().length() / 16) + 1);

        // loger.debug(line);
        StringBuilder lines = new StringBuilder();

        for (int i = 0; i < line; i++)
        {
            String li = Integer.toHexString(i) + "0";

            if (li.length() == 2)
            {
                li = "00" + li;
            }

            if (li.length() == 3)
            {
                li = "0" + li;
            }

            lines.append(li);
        }

        cdrBean.setLine(lines.toString());
        cdrBean.setBinary(binary.toString());
        cdrBean.setText(text.toString());

        //	loger.info("readBinaryToString: " + pktStr);
        //		loger.info("binary " + cdrBean.getBinary());
        //		loger.info("line " + cdrBean.getLine());
        return cdrBean;
    }

    private static void saveTreeFile(String fileName, String value)
    {
        //loger.debug(value);
        File file = new File(fileName);

        if (!file.getParentFile().exists())
        {
            file.getParentFile().mkdirs();
        }

        try
        {
            BufferedWriter bw = new BufferedWriter(new FileWriter(file));
            bw.write(value);
            bw.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    private Document getDetailedDecodingXML()
    {
        Document pktXml = null;
        String tsharkcmd = tshark + " -r " + filename + " " + pdml;
        InputStream in = RunTshark(tsharkcmd);

        try
        {
            pktXml = parse(in);

            //OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(new File("C:\\root\\d\\test.txt")));
            //osw.write(pktXml.asXML());
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        catch (DocumentException e)
        {
            e.printStackTrace();
        }

        return pktXml;
    }

    private Document getSummaryDecodingXML()
    {
        Document pktXml = null;
        String tsharkcmd = tshark + " -r " + filename + " " + psml;

        // loger.debug(filename);
        File file = new File(filename);
        int i = 0;

        while (file.length() == 0)
        {
            if (i > 20)
            {
                return pktXml;
            }

            try
            {
                i++;
                //loger.debug("file.length = " + file.length() + " : " + i);
                Thread.sleep(100);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }

        loger.debug("file.length = " + file.length());

        InputStream in = RunTshark(tsharkcmd);

        try
        {
            pktXml = readXMLFile(in);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        catch (DocumentException e)
        {
            e.printStackTrace();
        }

        try
        {
            in.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

        return pktXml;
    }	
	
	

}
